package com.digdes.calendar.gwt.client.widget;

import com.digdes.calendar.gwt.client.dto.EventDTOImpl;
import com.digdes.calendar.gwt.client.service.CalendarService;
import com.digdes.calendar.gwt.client.service.CalendarServiceAsync;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@SuppressWarnings("deprecation")
public class MonthWidget extends Composite implements TableListener, ClickListener {

    private final CalendarServiceAsync calendarService = GWT
            .create(CalendarService.class);
    private int rowS;
    private int cellS;
    private int todayRow;
    private int todayCell;
    private int displayToday;
    private NavBar navbar = new NavBar();
    private FlexTable monthGrid = new FlexTable();
    public CellGrid gridInCell;
    public List<CellGrid> gridInCellList = new ArrayList<CellGrid>();
    public Data data;
    public DateUtil date = new DateUtil();
    private EventsPanel eventsPanel = new EventsPanel();
    private AbsolutePanel aPanel = new AbsolutePanel();
    private List<EventLabel> eventsLabel = new ArrayList<EventLabel>();
    private List<EventDTOImpl> eventDTOList = new ArrayList<EventDTOImpl>();
    private EventLabel label;
    private ShowEventDBox eventDBox;
    //public CreateEventDialog createEventDialog;

    public MonthWidget() {
        //saveEvent();
        aPanel.setWidth("100%");
        aPanel.setHeight("100%");
        DockPanel outer = new DockPanel();
        setWidget(aPanel);
        monthGrid.setHeight("550px");
        monthGrid.setWidth("1010px");
        monthGrid.setCellPadding(0);
        monthGrid.setCellSpacing(0);
        monthGrid.setStyleName("monthGrid");

        Grid gridWeekHeader = new Grid(1, 7);
        gridWeekHeader.setWidth("1011px");
        gridWeekHeader.setCellPadding(0);
        gridWeekHeader.setCellSpacing(0);
        data = new Data();
        gridWeekHeader.setStyleName("weekheader");
        for (int i = 0; i < data.days.length; i++) {
            gridWeekHeader.setText(0, i, data.days[i]);
        }
        monthGrid.addTableListener(new TableListener() {
            public void onCellClicked(final SourcesTableEvents sender, final int row,
                                      final int cell) {
                selectedCell(row, cell);
            }
        });
        aPanel.add(outer);

        outer.add(navbar, DockPanel.NORTH);
        outer.add(gridWeekHeader, DockPanel.NORTH);

        outer.add(monthGrid, DockPanel.CENTER);
        outer.setStyleName("CalendarWidget");
        //drawCalendar();
    }

    private void clearCalendar() {
        for (EventLabel label : eventsLabel) {
            label.removeFromParent();
        }
        eventsPanel.getVp().clear();
        eventsPanel.setLabelDate("");
        gridInCellList.clear();
        eventDTOList.clear();
    }

    private void setParamsCells(int number, int i, int k, int day, int month, int year,
                                String styleCell, String styleCellInGrid) {
        gridInCell = new CellGrid(day, month, year);
        gridInCell.setNumber(number);
        gridInCell.setText(0, 0, String.valueOf(day));
        monthGrid.getCellFormatter().setStyleName(i, k, styleCell);
        gridInCell.getCellFormatter().addStyleName(0, 0, styleCellInGrid);
        gridInCell.setHeight("100%");
        gridInCell.setWidth(Util.WIDTH_MONTH_CELL + "px");
        gridInCell.setCellPadding(0);
        gridInCell.setCellSpacing(0);
        gridInCell.setText(1, 0, "");
        gridInCell.addTableListener(this);
        gridInCellList.add(gridInCell);
    }

    public void drawCalendar() {
        System.out.println("test");
        clearCalendar();
        int year = date.getYear();
        int month = date.getMonth();
        int today = date.getNowDay();
        int firstDay = new Date(year - 1900, month, 0).getDay();
        int numOfDays = date.getDaysInMonth(year, month);
        int numOfDaysPrev = date.getDaysInMonth(year, month - 1);
        int j = 0;
        int firstDayNextMonth = 1;

        setMonthListBox(month);
        setTitleYear(year);
        int number = 0;
        for (int i = 0; i < 6; i++) {
            for (int k = 0; k < 7; k++, j++) {

                int displayNum = (j - firstDay + 1);
                int displayNumPrev = (j + numOfDaysPrev - firstDay + 1);

                if (displayNum > numOfDays) {
                    if ((month + 1) == 12) {
                        setParamsCells(number, i, k, firstDayNextMonth, month - 11, year + 1, "empty", "dayCellLabelEmpty");
                    } else {
                        setParamsCells(number, i, k, firstDayNextMonth, month + 1, year, "empty", "dayCellLabelEmpty");
                    }
                    firstDayNextMonth++;
                } else if (j < firstDay) {
                    setParamsCells(number, i, k, displayNumPrev, month - 1, year, "empty", "dayCellLabelEmpty");
                } else {
                    setParamsCells(number, i, k, displayNum, month, year, "empty", "dayCellLabel");
                    if (displayNum == today) {
                        monthGrid.getCellFormatter().setStyleName(i, k, "empty");
                        monthGrid.getCellFormatter().addStyleName(i, k, "today");
                        todayRow = i;
                        todayCell = k;
                        displayToday = displayNum;
                    }
                }
                number++;
                monthGrid.setWidget(i, k, gridInCell);
            }//for (int k = 0; k < 7; k++, j++)
        }//for (int i = 0; i < 6; i++)
        getEvents();

    }

    private void getEvents() {
        final String sDate = gridInCellList.get(0).getDay() + "." +
                (gridInCellList.get(0).getMonth() + 1) + "." + gridInCellList.get(0).getYear();
        final String fDate = gridInCellList.get(41).getDay() + "." +
                (gridInCellList.get(41).getMonth() + 1) + "." + gridInCellList.get(41).getYear();

        calendarService.getEventsBetween(sDate, fDate, new AsyncCallback<ArrayList<EventDTOImpl>>() {
            public void onFailure(Throwable caught) {
            }

            public void onSuccess(ArrayList<EventDTOImpl> result) {
                eventDTOList.addAll(result);
                setEventsInCell();
                setEventInCellDay();
            }
        });
    }

    public void setEventsInCell() {
        for (CellGrid c : gridInCellList) {
            Date d = new Date(date.getYear() - 1900, c.getMonth(), c.getDay());
            for (EventDTOImpl e : eventDTOList) {
                Date eDateStart = new Date(e.getDateStart().getYear(), e.getDateStart().getMonth(),
                        e.getDateStart().getDate() - 1);
                if ((eDateStart.before(d) == true) && (e.getDateFinish().after(d) == true)) {
                    c.getEventDTOList().add(e);
                }
            }
        }
    }

    private void setEventInCellDay() {
        for (CellGrid c : gridInCellList) {
            c.setTop(Util.TOP_CELL_DEFAULT);
        }
        for (int k = 0; k < gridInCellList.size(); k++) {
            for (EventDTOImpl eventDTO : eventDTOList) {
                int dayS = eventDTO.getDateStart().getDate();
                int month = eventDTO.getDateStart().getMonth();
                if ((dayS == gridInCellList.get(k).getDay()) &&
                        month == (gridInCellList.get(k).getMonth())) {
                    drawEvent(eventDTO, k);
                }
            }
        }
    }

    public void drawEvent(EventDTOImpl eventDTO, int k) {
        if (gridInCellList.get(k).getTop()+15 < gridInCellList.get(k).getOffsetHeight()) {
            int left = gridInCellList.get(k).getAbsoluteLeft();
            int top = gridInCellList.get(k).getAbsoluteTop();
            int lengthEvent = getCountCell(eventDTO);
            int widthEvent = lengthEvent * Util.WIDTH_MONTH_CELL;
            if (widthEvent > 0)
                if (left + widthEvent > Util.LEFT_POSITION_GRID + Util.WIDTH_GRID) {
                    List<EventLabel> largeLabels = largeLabel(eventDTO, k, widthEvent);
                    for (EventLabel largeLabel : largeLabels) {
                        aPanel.add(largeLabel, largeLabel.getLeftPosition(),
                                largeLabel.getTopPosition() + largeLabel.getTop());
                        eventsLabel.add(largeLabel);
                    }

                } else {

                    label = new EventLabel(eventDTO);

                    if (lengthEvent > 1) {

                        label = bigLabel(eventDTO, k, widthEvent, lengthEvent);

                    } else {

                        label = smallLabel(eventDTO, widthEvent);
                    }
                    int topInCell = gridInCellList.get(k).getTop();
                    label.setStyleName("EventLabelMonth");
                    label.addClickListener(this);
                    label.setLeftPosition(left);
                    label.setTopPosition(top);

                    aPanel.add(label, label.getLeftPosition() - Util.MOVE_LEFT,
                            label.getTopPosition() + topInCell - Util.MOVE_TOP);

                    topInCell += Util.HEIGHT_LABEL;
                    if (k + lengthEvent < 42) {
                        for (int i = k; i < k + lengthEvent; i++) {
                            gridInCellList.get(i).setTop(topInCell);
                        }
                    }
                    eventsLabel.add(label);
                }
        }
    }

    private EventLabel smallLabel(EventDTOImpl eventDTO, int widthEvent) {

        String timeSEvent = eventDTO.getDateStart().getHours() + ":" +
                date.addZeroInMinutes(eventDTO.getDateStart().getMinutes());
        String timeFEvent = eventDTO.getDateFinish().getHours() + ":" +
                date.addZeroInMinutes(eventDTO.getDateFinish().getMinutes());
        String titleEvent = eventDTO.getNameEvent() + " (" + timeSEvent + "-" + timeFEvent + ")";

        label.setWidth(String.valueOf(widthEvent - 6));
        label.setText(titleEvent);
        return label;
    }

    private EventLabel bigLabel(EventDTOImpl eventDTO, int k, int widthEvent, int lengthEvent) {

        widthEvent = gridInCellList.get(k + lengthEvent - 1).getAbsoluteLeft() -
                gridInCellList.get(k).getAbsoluteLeft() + Util.WIDTH_MONTH_CELL;

        label.setWidth(String.valueOf(widthEvent - 6));
        label.setText(eventDTO.getNameEvent());

        return label;
    }

    private List<EventLabel> largeLabel(EventDTOImpl eventDTO, int k, int widthEvent) {
        List<EventLabel> bigLabels = new ArrayList<EventLabel>();
        int left = gridInCellList.get(k).getAbsoluteLeft() - Util.MOVE_LEFT;
        int top = gridInCellList.get(k).getAbsoluteTop() - Util.MOVE_TOP;
        int widthHead = Util.WIDTH_GRID - left;
        int widthTail = widthEvent - widthHead;
        int next = widthHead / Util.WIDTH_MONTH_CELL;
        int topN = gridInCellList.get(k).getTop();

        label = new EventLabel(eventDTO);
        label.addClickListener(this);
        label.setWidth(String.valueOf(widthHead));
        label.setText(eventDTO.getNameEvent());
        label.setStyleName("EventLabelMonth");
        label.setLeftPosition(left);
        label.setTopPosition(top);
        label.setTop(topN);
        bigLabels.add(label);

        topN += Util.HEIGHT_LABEL;
        for (int i = k; i < k + next; i++) {
            gridInCellList.get(i).setTop(topN);
        }

        int nextT = (widthTail / Util.WIDTH_MONTH_CELL);

        if (((k + next) < 42) && (gridInCellList.get(k + next).getAbsoluteLeft() + widthTail) >
                (Util.LEFT_POSITION_GRID + Util.WIDTH_GRID)) {
            List<EventLabel> tailLabels = largeLabel(eventDTO, k + next, widthTail);
            for (EventLabel tailLabel : tailLabels) {
                bigLabels.add(tailLabel);
            }

        } else if (k + next + nextT < 42) {
            int topT = gridInCellList.get(k + next).getTop();
            label = new EventLabel(eventDTO);
            label.addClickListener(this);
            widthTail = gridInCellList.get(k + next + nextT).getAbsoluteLeft() -
                    gridInCellList.get(k + next).getAbsoluteLeft() + Util.WIDTH_MONTH_CELL;
            label.setWidth(String.valueOf(widthTail - 6));
            label.setText(eventDTO.getNameEvent());
            label.setStyleName("EventLabelMonth");
            label.setTop(topT);
            label.setLeftPosition(gridInCellList.get(k + next).getAbsoluteLeft() - Util.MOVE_LEFT);
            label.setTopPosition(gridInCellList.get(k + next).getAbsoluteTop() - Util.MOVE_TOP);
            bigLabels.add(label);
            topT += Util.HEIGHT_LABEL;

            for (int i = k + next; i < k + next + nextT; i++) {
                gridInCellList.get(i).setTop(topT);
            }
        }
        return bigLabels;
    }

    private int getCountCell(EventDTOImpl eventDTO) {
        int countCell = 0;
        int daysInMonth;
        if (eventDTO.getDateFinish().getDate() >= eventDTO.getDateStart().getDate()) {
            countCell = eventDTO.getDateFinish().getDate() - eventDTO.getDateStart().getDate() + 1;
        } else if (eventDTO.getDateFinish().getDate() < eventDTO.getDateStart().getDate() &&
                (eventDTO.getDateStart().getMonth() == date.getMonth())) {
            daysInMonth = date.getDaysInMonth(date.getYear(), date.getMonth());
            countCell = eventDTO.getDateFinish().getDate() - (eventDTO.getDateStart().getDate() -
                    daysInMonth) + 1;
        } else if (eventDTO.getDateFinish().getDate() < eventDTO.getDateStart().getDate() &&
                (eventDTO.getDateStart().getMonth() == date.getMonth() - 1)) {
            daysInMonth = date.getDaysInMonth(date.getYear(), date.getMonth() - 1);
            countCell = eventDTO.getDateFinish().getDate() - (eventDTO.getDateStart().getDate() -
                    daysInMonth) + 1;
        }
        return countCell;
    }

    public void onClick(Widget sender) {
        final EventLabel label = (EventLabel) sender;
        eventDBox = new ShowEventDBox(label.getEventDTO());
        eventDBox.deleteBtn.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                deleteEvent(label);
            }
        });
        eventDBox.center();
    }

    private void deleteEvent(final EventLabel label) {
        eventDBox.deleteEvent(label, eventsLabel);
        drawCalendar();
        for (CellGrid c : gridInCellList) {
            c.getEventDTOList().remove(label.getEventDTO());
        }
    }

    public void onCellClicked(final SourcesTableEvents sender, final int row,
                              final int cell) {
        CellGrid cellGrid = (CellGrid) sender;
        eventsPanel.setData(cellGrid.getDay(), cellGrid.getMonth(), cellGrid.getYear(), cellGrid.getEventDTOList());
    }

    public void selectedCell(int row, int cell) {
        int today = date.getNowDay();
        monthGrid.getCellFormatter().setStyleName(row, cell, "selectCell");
        monthGrid.getCellFormatter().setStyleName(rowS, cellS, "cell");

        if (row == rowS && cell == cellS) {
            monthGrid.getCellFormatter().setStyleName(row, cell, "selectCell");
        }
        if (rowS == todayRow && cellS == todayCell && displayToday == today) {
            monthGrid.getCellFormatter().addStyleName(todayRow, todayCell, "today");
        }
        rowS = row;
        cellS = cell;
    }

    private void setMonthListBox(int month) {
        navbar.listBox.setSelectedIndex(month);
    }

    private void setTitleYear(int year) {
        navbar.titleYear.setText(String.valueOf(year));
    }

    public EventsPanel getEventsPanel() {
        return eventsPanel;
    }

    /*private void saveEvent() {
        createEventDialog = new CreateEventDialog(new CreateFileDialog(), new CreateParticipantDialog(),
                new Plan(), new CreatePlace());
        createEventDialog.save.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                int number = 0;
                for (CellGrid c : gridInCellList) {
                    if (c.getDay() == createEventDialog.newEvent().getDateStart().getDate()
                            && c.getMonth() == createEventDialog.newEvent().getDateStart().getMonth()) {
                        number = c.getNumber();
                    }
                    Date d = new Date(date.getYear() - 1900, c.getMonth(), c.getDay());
                    EventDTOImpl e = createEventDialog.newEvent();
                    Date eDateStart = new Date(e.getDateStart().getYear(), e.getDateStart().getMonth(),
                            e.getDateStart().getDate() - 1);
                    if ((eDateStart.before(d) == true) && (e.getDateFinish().after(d) == true)) {
                        c.getEventDTOList().add(e);
                    }
                }
                final int finalNumber = number;
                calendarService.saveEvent(createEventDialog.newEvent(), new AsyncCallback<EventDTOImpl>() {
                    public void onFailure(Throwable caught) {
                    }

                    public void onSuccess(EventDTOImpl result) {
                      //drawEvent(result, finalNumber);

                    }

                });

                createEventDialog.hide();
                   drawCalendar();
            }
        });
    }*/

    private class NavBar extends Composite implements ClickListener {

        public DockPanel bar = new DockPanel();
        public Button prevMonth = new Button("&lt;", this);
        public Button prevYear = new Button("«", this);
        public Button nextYear = new Button("»", this);
        public Button nextMonth = new Button("&gt;", this);
        public HTML titleYear = new HTML();
        public ListBox listBox = new ListBox();

        public NavBar() {
            setWidget(bar);
            bar.setStyleName("navbar");
            titleYear.setStyleName("header");
            data = new Data();
            for (int i = 0; i < data.months.length; i++) {
                listBox.addItem(data.months[i]);
            }
            listBox.setVisibleItemCount(0);
            listBox.addChangeHandler(new ChangeHandler() {
                public void onChange(ChangeEvent event) {
                    date.setMonth(listBox.getSelectedIndex());
                    drawCalendar();
                }
            });

            HorizontalPanel prevButtons = new HorizontalPanel();
            prevButtons.add(prevMonth);
            prevButtons.add(prevYear);

            HorizontalPanel nextButtons = new HorizontalPanel();
            nextButtons.add(nextYear);
            nextButtons.add(nextMonth);

            Grid gridTitleYear = new Grid(1, 2);

            gridTitleYear.setWidget(0, 0, listBox);
            gridTitleYear.setWidget(0, 1, titleYear);

            bar.add(prevButtons, DockPanel.WEST);
            bar.setCellHorizontalAlignment(prevButtons, DockPanel.ALIGN_LEFT);
            bar.add(nextButtons, DockPanel.EAST);
            bar.setCellHorizontalAlignment(nextButtons, DockPanel.ALIGN_RIGHT);
            bar.add(gridTitleYear, DockPanel.CENTER);
            bar.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);
            bar.setCellHorizontalAlignment(gridTitleYear,
                    HasAlignment.ALIGN_CENTER);
            bar.setCellVerticalAlignment(gridTitleYear,
                    HasAlignment.ALIGN_MIDDLE);
            bar.setCellWidth(gridTitleYear, "100%");
        }

        public void onClick(Widget sender) {
            if (sender == prevMonth) {
                date.prevMonth();
                listBox.setSelectedIndex(date.getMonth());
            } else if (sender == prevYear) {
                date.prevYear();
            } else if (sender == nextYear) {
                date.nextYear();
            } else if (sender == nextMonth) {
                date.nextMonth();
                listBox.setSelectedIndex(date.getMonth());
            }
            drawCalendar();
        }
    }

}
